package plp.imperative2.command;

import plp.expressions1.util.Tipo;
import plp.expressions2.expression.Expressao;
import plp.expressions2.expression.Id;
import plp.expressions2.expression.Valor;
import plp.expressions2.expression.ValorInteiro;
import plp.expressions2.memory.AmbienteCompilacao;
import plp.expressions2.memory.AmbienteExecucao;
import plp.expressions2.memory.VariavelJaDeclaradaException;
import plp.expressions2.memory.VariavelNaoDeclaradaException;
import plp.imperative2.expression.TipoArray;
import plp.imperative2.expression.ValorArray;

public class Indexacao extends Id {

	private Expressao indice;
	
	public Indexacao(String id, Expressao indice){
		super(id);
		this.indice = indice;
	}
	
	public Expressao getIndice() {
		return indice;
	}

	public void setIndice(Expressao indice) {
		this.indice = indice;
	}

	public Valor avaliar(AmbienteExecucao amb)
			throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
		ValorArray array = (ValorArray) amb.get(this);
		Valor indice = this.indice.avaliar(amb);
		Expressao exp = array.get(((ValorInteiro)indice).valor());
		return exp.avaliar(amb);
	}

	public boolean checaTipo(AmbienteCompilacao amb)
			throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
		boolean retorno = true;
		retorno = retorno && indice.checaTipo(amb) && indice.getTipo(amb).eInteiro();
		return (super.checaTipo(amb) && retorno);	
	}

	public Tipo getTipo(AmbienteCompilacao amb)
			throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
		Tipo tipo = amb.get(this);
		if(tipo instanceof TipoArray){
			tipo = ((TipoArray)tipo).getTipo();
		}
		return tipo;
	}

	public Expressao reduzir(AmbienteExecucao ambiente) {
		return super.reduzir(ambiente);
	}
	
	public Indexacao clone() {
		return new Indexacao(this.idName, this.indice);
	}
}
